<?php defined('SYSPATH') or die('No direct script access.');

class Model_ProductParser_Admitad extends Model_ProductParser_Abstract
{ 
    protected $filename = null;         // Название файла
    protected $shop     = null;
    protected $handler  = null;          // Дескриптор файла
    protected $charset  = null;          // Кодировка входного файла
    
    /**
    * Парсим товары магазина
    * 
    * @param Model_Shop $shop
    */
    public function parse($url, Model_Shop $shop = null)
    {          
        //$this->filename = APPPATH.'../data/tmp/123.xml';  
        $this->filename = APPPATH.'../data/tmp/'.time().'_'.mt_rand(1, 1000).'.xml';
        $this->_download_file($url, $this->filename);
        
        if ($shop) {
            $this->shop = $shop;
            $n = call_user_func(array($this, '_parse_shop'), $shop);
        } else {
            $n = call_user_func(array($this, '_parse_admitad')); 
        }   
        
        unlink($this->filename);
        return $n;
    }
    
    protected function _get_current_product_id()
    {
        $current_id = DB::select(array(DB::expr('MAX(id)'), 'max'))
            ->from('products')
            ->execute()
            ->as_array();
        $current_id = $current_id[0]['max'];
        return $current_id;
    }
    
    protected function _clean_brand_name($name)
    {
        return strtolower(str_replace(array('`', '\'', '®', '.', '-'), array('', '', '', '', ''), $name));    
    }    
    
    protected function _parse_admitad()
    {
        $this->_add_nl_to_offers();
        $this->_open_file();   
        $this->_detect_charset();
        
        while ($category_data = $this->_get_category()) {
            $category_id = $this->_get_category_id($category_data);
            $category_name = $this->_get_category_name($category_data);
            $parent_id   = $this->_get_category_parent_id($category_data);
            
            try {
                //echo $category_id.' - '.$category_name.' - '.$parent_id."\n";
                DB::insert('categories', array('id', 'parent_id', 'name'))
                    ->values(array($category_id, $parent_id, $category_name))->execute();
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    //continue;
                } else {
                    die($e->getMessage());
                }
            }
        }
        
        $this->_process_category_childs(); 
        
        $brands = array();
        $tmp_brands = DB::select()
                    ->from('brands')
                    ->execute()
                    ->as_array();
        foreach ($tmp_brands as $brand) {
            $brands[$brand['url']] = $brand['id'];    
        }
            
        // Добавляем товары
        $n = 0;
        $changed_n = 0;       
        $current_id = $this->_get_current_product_id();
        
        while ($product_data = $this->_get_product()) {          
            $product_id = $this->_get_product_id($product_data);
            $original_id = $this->_get_product_original_id($product_data);
            $available   = $this->_get_product_available($product_data); 
            
            $brand  = $this->_get_product_vendor($product_data);
            if ($brand) {
                $brand_url  = Model_Main::translit($brand);
                $brand_url  = str_replace('-amp-', '-and-', $brand_url);
                
                if (isset($brands[$brand_url])) {
                    $brand_id = $brands[$brand_url];    
                } else {
                    try {
                        list($brand_id, $affected_rows) = DB::insert('brands', array('name', 'url'))
                                                                ->values(array($brand, $brand_url))->execute();
                        $brands[$brand_url] = $brand_id;
                    } catch (Database_Exception $e) {
                        if (strstr($e->getMessage(), 'Duplicate entry') !== false) {

                        } else {
                            die($e->getMessage());
                        }
                    }
                }
            } else {
                $brand_id = 0;
            }
            
            $category_id = $this->_get_product_category_id($product_data);
            $original_category_id = 0;
            
            $shop_id    = $this->_get_shop_id($product_data);
            if (in_array($shop_id, array(1001, 4102, 3761, 743, 5057, 5533))) {
                continue;
            }
            $shop_name  = $this->_get_shop_name($product_data);
            $shop_url  = Model_Main::translit($shop_name);
            $shop_url  = str_replace('-amp-', '-and-', $shop_url);
            try {
                DB::insert('shops', array('id', 'name', 'url'))
                    ->values(array($shop_id, $shop_name, $shop_url))->execute();
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {

                } else {
                    die('#'.$product_id.' - '.$e->getMessage());
                }
            }
            
            $name        = $this->_get_product_name($product_data);
            $url         = $this->_get_product_url($product_data);
            
            $thumbnail   = $this->_get_product_thumbnail($product_data);
            $picture     = $this->_get_product_picture($product_data);
            $picture_orig = $this->_get_product_picture_orig($product_data);
            
            $description = $this->_get_product_description($product_data);
            $price       = $this->_get_product_price($product_data);
            $currency    = $this->_get_product_currency($product_data);
            
            $params      = $this->_get_product_params($product_data);
            $clean_params = Model_Product::get_clean_params($params);
            $type_prefix = $this->_get_product_type_prefix($product_data);
            $vendor_code = $this->_get_product_vendor_code($product_data);
            $delivery    = $this->_get_product_delivery($product_data);
            $pickup      = $this->_get_product_pickup($product_data);
            $modified_time = $this->_get_product_modified_time($product_data);
            
            
            
            try {
               /* echo "id - $product_id\n";
                echo "original_id - $original_id\n";
                echo "brand - $brand\n";
                echo "brand_id - $brand_id\n";             
                echo "category - $category_id\n";
                echo "shop - $shop_name\n"; 
                echo "shop_id - $shop_id\n"; 
                echo "name - $name\n"; 
                echo "url - $url\n";           
                echo "thumbnail - $thumbnail\n"; 
                echo "picture - $picture\n"; 
                echo "picture_orig - $picture_orig\n"; 
                echo "description - $description\n";
                echo "price - $price\n";
                echo "currency - $currency\n";              
                echo "params - $params\n"; 
                echo "type_prefix - $type_prefix\n";             
                echo "vendor_code - $vendor_code\n";                
                echo "delivery - $delivery\n";  
                echo "pickup - $pickup\n";
                echo "modified_time - $modified_time\n"; */
                
                if ($available && $name && $url) {
                    $current_id++;  
                    
                    DB::insert('available_products', array('original_id', 'shop_id'))
                            ->values(array($original_id, $shop_id))->execute();
                    
                    DB::insert('products', array('id', 'admitad_id', 'original_id', 'brand', 'brand_id', 'category_id', 'original_category_id', 'shop_id', 'name', 'url', 'thumbnail',
                        'picture', 'picture_orig', 'price', 'currency', 'type_prefix', 'vendor_code', 'delivery', 'pickup', 'modified_time'))
                            ->values(array($current_id, $product_id, $original_id, $brand, $brand_id, $category_id, $original_category_id, $shop_id, $name, $url, $thumbnail,
                            $picture, $picture_orig, $price, $currency, $type_prefix, $vendor_code, $delivery, $pickup, $modified_time))->execute();
                    
                    DB::insert('product_data', array('product_id', 'description', 'params', 'clean_params'))
                            ->values(array($current_id, $description, $params, $clean_params))->execute();
                    $n++;
                }
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    $current_id--;      // возвращаем назад идентификатор, т.к. он увеличился, но запись не вставилась
                    
                    $changed_rows = DB::update('products')
                            ->set(array('price' => $price))
                            ->where('original_id', '=', $original_id)
                            ->where('shop_id', '=', $shop_id)
                            ->execute();
                    if ($changed_rows) {    // цена изменилась
                        $product = ORM::factory('product')
                                    ->where('original_id', '=', $original_id)
                                    ->where('shop_id', '=', $shop_id)
                                    ->find();
                        DB::delete('product_coupons')
                            ->where('product_id', '=', $product->id)
                            ->execute();
                        $changed_n++;   
                    }
                } else {
                    die($e->getMessage());   
                }
            }
        } 
              
        $this->_close_file();
        echo 'Changed - '.$changed_n."\n"; 
        return $n;     
    }
    
    protected function _parse_shop($shop)
    {
        $shop_id = $shop->id;
        $this->_add_nl_to_offers();
        $this->_open_file();   
        $this->_detect_charset();
        
        $brands = array();
        $tmp_brands = DB::select()
                    ->from('brands')
                    ->execute()
                    ->as_array();
        foreach ($tmp_brands as $brand) {
            $brands[strtolower($brand['url'])] = $brand['id'];    
        }
            
        // Добавляем товары
        $n = 0;
        $changed_n = 0;
        $current_id = $this->_get_current_product_id();
        
        while ($product_data = $this->_get_product()) {
            $product_id = 0;
            $original_id = $this->_get_product_id($product_data);
            $available   = $this->_get_product_available($product_data);    
            
            $brand  = $this->_get_product_vendor($product_data);
            if ($brand) {
                $brand_url  = Model_Main::translit($brand);
                $brand_url  = str_replace('-amp-', '-and-', $brand_url);
                
                if (isset($brands[$brand_url])) {
                    $brand_id = $brands[$brand_url];    
                } else {
                    try {
                        list($brand_id, $affected_rows) = DB::insert('brands', array('name', 'url'))
                                                                ->values(array($brand, $brand_url))->execute();
                        $brands[$brand_url] = $brand_id;
                    } catch (Database_Exception $e) {
                        if (strstr($e->getMessage(), 'Duplicate entry') !== false) {

                        } else {
                            die($e->getMessage());
                        }
                    }
                }
            } else {
                $brand_id = 0;
            }
            
            $original_category_id = $this->_get_product_category_id($product_data);
            $category_id = 0;
            if (method_exists($this, '_get_'.$shop_id.'_category')) {
                $category_id = call_user_func(array($this, '_get_'.$shop_id.'_category'), $original_category_id);
            }    
            
            $name        = $this->_get_product_name($product_data);
            
            $url         = $this->_get_product_url($product_data);
            // !!!
            //$url         = str_replace('http://ad.admitad.com/goto/1d9ed345ddea57d2938cdc28f2033d/?ulp=',
            //                           'http://n.actionpay.ru/click/52446a13fc3f5b858c000031/54232/subaccount/url=', $url);
            
            $thumbnail   = $this->_get_product_thumbnail($product_data);
            $picture     = $this->_get_product_picture($product_data);
            $picture_orig = $this->_get_product_picture_orig($product_data);
            
            $images      = $this->_get_product_pictures($product_data);
            
            $description = $this->_get_product_description($product_data);
            $price       = $this->_get_product_price($product_data);
            $currency    = $this->_get_product_currency($product_data);
            
            $params      = $this->_get_product_params($product_data);
            $clean_params = Model_Product::get_clean_params($params);
            $type_prefix = $this->_get_product_type_prefix($product_data);
            $vendor_code = $this->_get_product_vendor_code($product_data);
            $delivery    = $this->_get_product_delivery($product_data);
            $pickup      = $this->_get_product_pickup($product_data);
            $modified_time = $this->_get_product_modified_time($product_data);
            
            // -------------- место для костылей ------------------
            if ($shop_id == 743) {
                $available = true;    
            }
            
            if ($brand && in_array($shop_id, array(4102, 5057))) {
                $name .= ' '.$brand;    
            }
            if ($brand && $shop_id == 743) {
                $_model = $this->_get_product_model($product_data);
                $name  = $_model.' '.$brand;   
            }
            
            if ($shop_id == 5057) {
                $_params = json_decode($params, true);
                $gender = null;
                if (isset($_params['Пол'])) {
                    $gender = $_params['Пол'];    
                }
                if (isset($_params['пол'])) {
                    $gender = $_params['пол'];    
                }
                if ($gender && $gender != 'женщина') {
                    $category_id = 0;    
                }
            }
            // ----------------------------------------------------  
            
            try {
               /* echo "id - $product_id\n";
                echo "original_id - $original_id\n";
                echo "brand - $brand\n";
                echo "brand_id - $brand_id\n";             
                echo "category - $category_id\n";
                echo "shop - $shop_name\n"; 
                echo "shop_id - $shop_id\n"; 
                echo "name - $name\n"; 
                echo "url - $url\n";           
                echo "thumbnail - $thumbnail\n"; 
                echo "picture - $picture\n"; 
                echo "picture_orig - $picture_orig\n"; 
                echo "description - $description\n";
                echo "price - $price\n";
                echo "currency - $currency\n";              
                echo "params - $params\n"; 
                echo "type_prefix - $type_prefix\n";             
                echo "vendor_code - $vendor_code\n";                
                echo "delivery - $delivery\n";  
                echo "pickup - $pickup\n";
                echo "modified_time - $modified_time\n"; */
                
				if ($available && $name && $url) {
                    $current_id++;  
                    
                    DB::insert('available_products', array('original_id', 'shop_id'))
                            ->values(array($original_id, $shop_id))->execute();
                    
					DB::insert('products', array('id', 'admitad_id', 'original_id', 'brand', 'brand_id', 'category_id', 'original_category_id', 'shop_id', 'name', 'url', 'thumbnail',
						'picture', 'picture_orig', 'price', 'currency', 'type_prefix', 'vendor_code', 'delivery', 'pickup', 'modified_time'))
							->values(array($current_id, $product_id, $original_id, $brand, $brand_id, $category_id, $original_category_id, $shop_id, $name, $url, $thumbnail,
							$picture, $picture_orig, $price, $currency, $type_prefix, $vendor_code, $delivery, $pickup, $modified_time))->execute();
                    
                    DB::insert('product_data', array('product_id', 'description', 'images', 'params', 'clean_params'))
                            ->values(array($current_id, $description, $images, $params, $clean_params))->execute();
                    $n++;
				}
			} catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    $current_id--;      // возвращаем назад идентификатор, т.к. он увеличился, но запись не вставилась
                    
                    DB::update('products')
                            ->set(array('category_id' => $category_id, 'original_category_id' => $original_category_id))
                            ->where('original_id', '=', $original_id)
                            ->where('shop_id', '=', $shop_id)
                            ->execute();
                    /*DB::update('products')
                            ->set(array('brand' => $brand, 'brand_id' => $brand_id))
                            ->where('original_id', '=', $original_id)
                            ->where('shop_id', '=', $shop_id)
                            ->execute();   */
                    $changed_rows = DB::update('products')
                            ->set(array('price' => $price))
                            ->where('original_id', '=', $original_id)
                            ->where('shop_id', '=', $shop_id)
                            ->execute();
                    if ($changed_rows) {    // цена изменилась
                        $product = ORM::factory('product')
                                    ->where('original_id', '=', $original_id)
                                    ->where('shop_id', '=', $shop_id)
                                    ->find();
                        DB::delete('product_coupons')
                            ->where('product_id', '=', $product->id)
                            ->execute();
                        $changed_n++;   
                    }
                } else {
                    die($e->getMessage());
                }
            }
        }       
        $this->_close_file(); 
        echo 'Changed - '.$changed_n."\n";
        return $n;     
    }         
    
    protected function _get_product_id(&$product_data)
    {
        $product_id = $this->_cut_str(' id="', '"', $product_data); 
        return $product_id; 
    }
    
    protected function _get_product_original_id(&$product_data)
    {
        $original_id = $this->_cut_str(' original_id="', '"', $product_data); 
        return $original_id;     
    }
    
    protected function _get_product_available(&$product_data)
    {
        $available = $this->_cut_str(' available="', '"', $product_data);
        if ($available == 'false') {
            return false;
        } 
        return true;;     
    }
    
    protected function _get_product_category_id(&$product_data)
    {
        $category_id = $this->_cut_str('<categoryId>', '</categoryId>', $product_data); 
		if ($category_id) {
			return $category_id;
		}
		return 0;
    }
    
    protected function _get_product_url(&$product_data)
    {
        $url = $this->_cut_str('<url>', '</url>', $product_data);
        return $url;
    }
    
    protected function _get_product_name(&$product_data)
    {
        $name = $this->_cut_str('<name>', '</name>', $product_data);
        if ($name = trim($name)) {
            return $this->_cut_quotes($name);    
        }
        return null;  
    }
    
    protected function _get_product_model(&$product_data)
    {
        $model = $this->_cut_str('<model>', '</model>', $product_data);
        return $model;  
    }
    
    protected function _get_product_thumbnail(&$product_data)
    {
        $url = $this->_cut_str('<thumbnail>', '</thumbnail>', $product_data);
        return $url;  
    }
    
    protected function _get_product_picture($product_data)
    {
        $url = $this->_cut_str('<picture>', '</picture>', $product_data);
        return $url;  
    }
    
    protected function _get_product_pictures(&$product_data)
    {
        $pictures = array();
        while ($item = $this->_cut_str('<picture>', '</picture>', $product_data)) {
            $pictures[] = $item;
        }     
        if(count($pictures)) {
            return implode('||', $pictures);
        }
        return null; 
    }
    
    protected function _get_product_picture_orig(&$product_data)
    {
        $url = $this->_cut_str('<picture_orig>', '</picture_orig>', $product_data);
        return $url;    
    }
    
    protected function _get_product_vendor(&$product_data)
    {
        $vendor = $this->_cut_str('<vendor>', '</vendor>', $product_data);
        if ($vendor) {
            return $this->_cut_quotes($vendor);    
        }
        return null;
    }
    
    protected function _get_product_price(&$product_data)
    {
        $price = $this->_cut_str('<price>', '</price>', $product_data);
        if ($price) {
            return $price;
        }
        return 0;    
    }
    
    protected function _get_product_currency(&$product_data)
    {
        $currency = $this->_cut_str('<currencyId>', '</currencyId>', $product_data);
        if ($currency) {
            return $currency;
        }
        return null;    
    }
    
    protected function _get_product_params(&$product_data)
    {
        $params = array();
        while ($item = $this->_cut_str('<param ', '/param>', $product_data)) {
            $name  = $this->_cut_str('name="', '"', $item);
            $value = $this->_cut_str('>', '<', $item);
            $params[$name] = $value;
        }     
        if(count($params)) {
            return json_encode($params);
        }
        return null;
    }
    
    protected function _get_product_type_prefix(&$product_data)
    {
        $prefix = $this->_cut_str('<typePrefix>', '</typePrefix>', $product_data);
        return $prefix;  
    }
    
    protected function _get_product_vendor_code(&$product_data) 
    {
        $code = $this->_cut_str('<vendorCode>', '</vendorCode>', $product_data);
        return $code;    
    }
    
    protected function _get_product_delivery(&$product_data) 
    {
        $delivery = $this->_cut_str('<delivery>', '</delivery>', $product_data);
        if ($delivery == 'true') {
            return 1;     
        }
        return 0;    
    }
    
    protected function _get_product_pickup(&$product_data) 
    {
        $pickup = $this->_cut_str('<pickup>', '</pickup>', $product_data);
        if ($pickup == 'true') {
            return 1;     
        }
        return 0;    
    }
    
    protected function _get_product_modified_time(&$product_data)
    {
        $time = $this->_cut_str('<modified_time>', '</modified_time>', $product_data);
        return (int)$time;   
    }
               
    protected function _get_product_description(&$product_data)
    {
        $description = $this->_cut_str('<description>', '</description>', $product_data);
        if ($description) {
            return $description;
        }
        return null;   
    }
    
    protected function _get_category_id(&$category_data)
    {
        $category_id = $this->_cut_str('id="', '"', $category_data);
        return $category_id;  
    }
    
    protected function _get_category_name(&$category_data)
    {
        $name = $this->_cut_str('>', '<', $category_data);
        return $this->_cut_quotes($name);  
    }
    
    protected function _get_category_parent_id(&$category_data)
    {
        $parent_id = $this->_cut_str('parentId="', '"', $category_data);
        if (!$parent_id) {
            return 0;
        }
        return $parent_id;  
    }
    
    protected function _get_shop_id(&$product_data)
    {
        $shop_id = $this->_cut_str('<advcampaign_id>', '</advcampaign_id>', $product_data); 
        return $shop_id;   
    }
    
    protected function _get_shop_name($product_data)
    {
        $name = $this->_cut_str('<advcampaign_name>', '</advcampaign_name>', $product_data); 
        return $name;     
    }
    
    protected function _add_nl_to_offers()
    {
        $in_handler   = fopen($this->filename, 'r+');
        
        $out_filename = APPPATH.'../data/tmp/tmp'.time().'_'.mt_rand(0, 1000).'.xml';
        $out_handler  = fopen($out_filename, 'w+'); 
        
        while($str = fgets($in_handler)) {
            $str = str_replace('><', ">\r\n<", $str);
            fputs($out_handler, $str);    
        }
        
        unset($this->filename);
        $this->filename = $out_filename;
    }
    
    protected function _open_file()
    {
        $result = $this->handler = fopen($this->filename, 'r+'); 
        if (!$result) {
            throw new Model_Exception('Не удалось открыть файл');
        }
        return $result; 
    }
    
    protected function _detect_charset()
    {
        $str = fgets($this->handler);
        $charset = $this->_cut_str(' encoding="', '"', $str);
        
        if ($charset) {
            $this->charset = mb_strtolower($charset);
        } else {
            $this->charset = 'utf-8';
        }
    }
    
    protected function _encode($str)
    {
        if ($this->charset == 'utf-8') {
            return $str;
        }
        
        return iconv($this->charset, 'utf-8', $str);
    }
    
    protected function _get_product()
    {
        $data = null;
        while($str = fgets($this->handler)) {              
            if (strstr($str, '<offer') !== false) {
                $data = $str;
                
                $str = fgets($this->handler);
                while (strstr($str, '</offer>') === false) {
                    $data .= $str;
                    $str   = fgets($this->handler);
                }
                if (strstr($str, '</offers>') !== false) {
                    return false;    
                }
                fseek($this->handler, -mb_strlen($str), SEEK_CUR);
                
                break;
            }
        }     
        return $this->_encode($data);
    }
    
    protected function _get_category()
    {
        $data = null;
        while($str = fgets($this->handler)) {  
            if (strstr($str, '</categories>') !== false) {
                return null;    
            }            
            if (strstr($str, '<category ') !== false) {
                $data = $str;
                
                while (strstr($str, '/category>') === false) {
                    $data .= $str;
                    $str   = fgets($this->handler);
                }
                //fseek($this->handler, -mb_strlen($str), SEEK_CUR);
                
                break;
            }
        }     
        return $this->_encode($data);
    }
    
    protected function _get_shop()
    {
        $data = null;
        while($str = fgets($this->handler)) {                 
            if (strstr($str, '<shop ') !== false) {
                $data = $str;
                
                do {
                    $str   = fgets($this->handler);
                    $data .= $str;
                } while (strstr($str, '</regions_geotarget>') === false);
                //fseek($this->handler, -mb_strlen($str), SEEK_CUR);
                
                break;
            }
        }  
        return $this->_encode($data);   
    } 
    
    protected function _close_file()
    {
        if (!fclose($this->handler)) {
            throw new Model_Exception('Не удалось закрыть файл');   
        }  
        return true; 
    }
    
    protected function _cut_quotes($str)
    {
        return trim(str_replace(array('<![CDATA[', ']]>'), '', $str));    
    }
    
    protected function _process_category_childs()
    {
        function get_childs($category, &$result) {
            $childs = DB::select()
                ->from('categories')
                ->where('parent_id', '=', $category['id'])
                ->execute()
                ->as_array();
            foreach ($childs as $child) {
                $result[] = $child['id']; 
                get_childs($child, $result);   
            }   
        }
        
        $result = array();
        $categories = DB::select()
                ->from('categories')
                ->execute()
                ->as_array();
        $result = array();
        foreach ($categories as $cat) {
            $result[$cat['id']] = array();
            get_childs($cat, $result[$cat['id']]);
        }
        
        foreach ($categories as $cat) {
            if (count($result[$cat['id']])) {
                DB::update('categories')
                        ->value('childs', implode(',', $result[$cat['id']]))
                        ->where('id', '=', $cat['id'])
                        ->execute();
            }
        }
    }
}